﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Atmk.WaterMeter.MIS.Commons.Interfaces.Logic;
using Atmk.WaterMeter.MIS.Commons.Interfaces.Logic.Statistics;
using Atmk.WaterMeter.MIS.Commons.Utils;
using Atmk.WaterMeter.MIS.Entities;
using Atmk.WaterMeter.MIS.Entities.Enums;
using Atmk.WaterMeter.MIS.LogicTestForm.Common;
using Microsoft.EntityFrameworkCore.Internal;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using WeifenLuo.WinFormsUI.Docking;

namespace Atmk.WaterMeter.MIS.LogicTestForm.Views.ReadDataMock
{
    public partial class WriteDataMock : DockContent
    {
        private readonly IDataStoreLogic _dataStoreLogic;
        private static readonly ILogger _Logger = LogManager.GetCurrentClassLogger();
        private readonly IWaterConsumptionLogic _waterConsumptionLogic;
        private readonly IAccountsLogic _accountsLogic;
        private readonly IOwnersLogic _ownersLogic;
        private readonly IRegionLogic _regionLogic;
        private readonly IWaterMetersLogic _waterMetersLogic;
        private readonly IUserCenterLogic _userCenterLogic;
        private readonly ILoginLogic _loginLogic;
        private readonly IDistrictLogic _districtLogic;
        private readonly IOwnerMeterLogic _ownerMeterLogic;
        private readonly IReponstoryManageLogic _reponstoryManageLogic;
        private readonly IQueryDatasLogic _queryDatasLogic;

        private string projectId = "";
        private string currentDis = "";
        private string currentdisName = "";
        private Queue<ulong> hourhistoryRead = new Queue<ulong>();
        private bool IsWrite;

        public WriteDataMock(IWaterConsumptionLogic waterConsumptionLogic,
            IAccountsLogic accountsLogic,
            IOwnersLogic ownersLogic,
            IRegionLogic regionLogic,
            IWaterMetersLogic waterMetersLogic,
            IDistrictLogic districtLogic,
            IUserCenterLogic userCenterLogic,
            ILoginLogic loginLogic,
            IDataStoreLogic dataStoreLogic,
            IQueryDatasLogic queryDatasLogic,
            IReponstoryManageLogic reponstoryManageLogic,
        IOwnerMeterLogic ownerMeterLogic)
        {
            _dataStoreLogic = dataStoreLogic;
            _waterConsumptionLogic = waterConsumptionLogic;
            _accountsLogic = accountsLogic;
            _ownersLogic = ownersLogic;
            _regionLogic = regionLogic;
            _districtLogic = districtLogic;
            _waterMetersLogic = waterMetersLogic;
            _userCenterLogic = userCenterLogic;
            _loginLogic = loginLogic;
            _ownerMeterLogic = ownerMeterLogic;
            _queryDatasLogic = queryDatasLogic;
            _reponstoryManageLogic = reponstoryManageLogic;
            InitializeComponent();
            BindingEventArgs();
            DaysCount();
            BindControlDatas();
        }

        private void BindControlDatas()
        {
            try
            {
                _Logger.Info("超级管理员登陆");
                _loginLogic.LoginMatching("admin", "123456", out string staffId, out string roleId, out string areaId);
                var projects = _userCenterLogic.SelectAreas(staffId, "");
                var list = new Dictionary<string, string>();
                projects.ForEach(s => list[s.id] = s.siteName);
                IntPtr i = this.Handle;
                BindList(_comboxProject, list);
                _comboxProject.SelectedIndex = 0;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                _Logger.Error(e);
            }
        }

        private void HourHistyInit()
        {
            hourhistoryRead.Clear();
            for (int i = 0; i < 12; i++)
            {
                hourhistoryRead.Enqueue(0);
            }
        }

        private void BindingEventArgs()
        {
            _comboxProject.SelectedIndexChanged += (s, e) =>
            {
                projectId = _comboxProject.SelectedValue.ToString();
                if (!Guid.TryParse(projectId, out var g))
                    return;
                var areaList = _districtLogic.GetDistricts(g);
                var list = new Dictionary<string, string>();
                areaList.ForEach(d => list[d.Id.ToString()] = d.Name);
                IntPtr i = this.Handle;
                BindList(_DistcomboBox, list);
            };
            _DistcomboBox.SelectedIndexChanged += (s, e) =>
            {
                Info($"选中片区{_DistcomboBox.SelectedText},片区主键{_DistcomboBox.SelectedValue.ToString()}");
            };
            _WriteReadingBtn.Click += (s, e) =>
            {
                currentDis = _DistcomboBox.SelectedValue.ToString();
                currentdisName = _DistcomboBox.SelectedText.ToString();
                StartWrite();
            };
            _RemoveRecords.Click += (s, e) =>
            {
                currentDis = _DistcomboBox.SelectedValue.ToString();
                var numbers = MeterNumbers().ToArray();
                var mess = "清除抄表记录" + (_reponstoryManageLogic.MeterRecordClear(numbers) ? "成功" : "失败");
                Info(mess);
            };
            _clearBtn.Click += (s, e) =>
            {
                _InfoText.Text = "";
            };
            _FirstDateTimePicker.ValueChanged += (s, e) =>
            {
                DaysCount();
            };
            _EndDateTimePicker.ValueChanged += (s, e) =>
            {
                DaysCount();
            };
        }

        private void DaysCount()
        {
            var start = _FirstDateTimePicker.Value;
            var end = _EndDateTimePicker.Value;
            if (start > end)
            {
                Info("开始时间不能大于结束时间");
                start = end.AddDays(-1);
            }
            else if (end.Date>DateTime.Now.Date)
            {
                Info("结束时间不能大于当前日期");
                end = DateTime.Now.Date;
            }
            else
            {
                _RunDaysText.Text = (end - start).Days.ToString();
            }
        }

        private void StartWrite()
        {
            if (!IsWrite)
            {
                IsWrite = true;
                var numbers = MeterNumbers();
                new Thread(()=>Run(numbers)).Start();
            }
            else
            {
                MessageBox.Show(@"已有写入线程运行");
            }
        }

        private List<string> MeterNumbers()
        {
            var obj = _ownerMeterLogic.Select(0, projectId, currentDis, "",1, 200, out int count);
            var ja = JArray.Parse(JsonConvert.SerializeObject(obj));
            var meterNumbers = ja.Select(o => ((JObject)((JObject)o)["WaterMeter"])["meterNumber"].ToString())
                .ToList();
            return meterNumbers;
        }

        private void Run(List<string> meterNumbers)
        {
            try
            {
                Info("开始写入数据");
                SafeControl(false);
                int n = 0;
                int d = meterNumbers.Count;
                foreach (var t in meterNumbers)
                {
                    n++;
                    var nearLoad = LoadNearReading(t, out var hundredvalue, out var dtNear);
                    if (nearLoad)
                        Info($"获取水表{t},最近读数*百倍:{hundredvalue},抄表时间{dtNear.ToString("s").Replace('T',' ')}");
                    else
                    {
                        int.TryParse(_FirstReading.Text, out hundredvalue);
                        dtNear = _FirstDateTimePicker.Value;
                    }
                    Info($"写入水表{t}数据");
                    MeterRun(t,hundredvalue,dtNear);
                    InfoChange($"片区{currentdisName}写入进度{MathsHelper.PercentString(n,d)}");
                }

                Info("数据写入结束");
                ProgressBarSet(0,100);
                InfoChange("");
            }
            catch (Exception e)
            {
                Info(e.Message);
            }
            finally
            {
                IsWrite = false;
                SafeControl(true);
            }
        }

        private bool LoadNearReading(string meterNumber,out int hundredvalue,out DateTime dtNear)
        {
            dtNear = DateTime.Now;
            hundredvalue = 0;
             var record = _queryDatasLogic.SelectNearRecord(meterNumber);
            if (record.Number == null && record.RecordState == RecordStateEnum.Deleted)
            {
                return false;
            }
            dtNear = record.ReadTime;
            hundredvalue = (int) record.Value * 100;
            return true;
        }

        private void MeterRun(string meterNumber,int value,DateTime date)
        {
           int.TryParse(_RunDaysText.Text, out var rundays);
           HourHistyInit();
            Info($"水表{meterNumber}开始录入数据");
            int n = 0;
            int d = rundays;
            ProgressBarSet(n, d);
            for (int i = 0; i < rundays; i++)
            {
                if (date > DateTime.Now)
                {
                    //Info("抄表时间大于当前时间，不建议写入，录入时间:" + date);
                    return;
                }
                Write((ulong) value, meterNumber, date);
                ProgressBarRun(i);
                //Info("水表值:" + value);
                value += new Random(Simple.GetRandomSeed()).Next(11, 59);
                hourhistoryRead.Dequeue();
                hourhistoryRead.Enqueue((ulong) value);
                date = date.AddDays(1);
            }
        }

        private void Write(ulong value, string number, DateTime date)
        {
            var d = new DeviceData
            {
                valve = 1,
                voltage = new Random(Simple.GetRandomSeed()).Next(360, 365),
                voltageState = 0,
                warning = 0,
                current = Get64String(value),
                history = GetHistoryValue(hourhistoryRead)
            };
            _dataStoreLogic.MeterRecordSave(number, d, date);
        }

        private string GetHistoryValue(Queue<ulong> readQueue)
        {
            var list = readQueue.Select(Get64String).ToList();
            return string.Join("", list.ToArray());
        }

        private string Get64String(ulong value)
        {
            return Convert.ToBase64String(BitConverter.GetBytes(value
            ).Reverse().Skip(2).Reverse().ToArray());
        }

        private void Info(string message, bool rn = true)
        {
            Invoke((EventHandler) delegate
            {
                if (rn)
                    _InfoText.Text =
                        _InfoText.Text.Insert(0, $"{DateTime.Now.ToShortTimeString()}:" + message + "\r\n");
                else
                {
                    _InfoText.AppendText(message);
                }
            });
        }

        private void ProgressBarSet(int n,int d)
        {
            Invoke((EventHandler)delegate
            {
                _ProgressBar.Minimum = n;
                _ProgressBar.Maximum = d;
                _ProgressBar.Value = n;
            });
        }
        private void ProgressBarRun(int n)
        {
            Invoke((EventHandler)delegate
            {
                _ProgressBar.Value = n;
            });
        }

        private void SafeControl(bool state)
        {
            Invoke((EventHandler)delegate
            {
                _comboxProject.Enabled = state;
                _DistcomboBox.Enabled = state;
                _FirstDateTimePicker.Enabled = state;
                _EndDateTimePicker.Enabled = state;
                _WriteReadingBtn.Enabled = state;
                _RemoveRecords.Enabled = state;
            });
        }

        private void InfoChange(string message)
        {
            Invoke((EventHandler)delegate
            {
                _RunPerLabel.Text = message;
            });
        }

        private void BindList(CheckedListBox clbBox, Dictionary<string, string> value)
        {
            Invoke((EventHandler) delegate
            {
                var item = value.Select(a => new
                {
                    key = a.Key,
                    value = a.Value
                });
                clbBox.DataSource = item.ToList();
                clbBox.DisplayMember = "value";
                clbBox.ValueMember = "key";
            });
        }

        private void BindList(ComboBox comboBox, Dictionary<string, string> value)
        {
            Invoke((EventHandler) delegate
            {
                var item = value.Select(a => new
                {
                    key = a.Key,
                    value = a.Value
                });
                comboBox.DataSource = item.ToList();
                comboBox.DisplayMember = "value";
                comboBox.ValueMember = "key";
            });
        }
    }
}